package main

import (
	"flag"
	"fmt"
	"math/big"

	"gitee.com/thubcc/blockchain/constant"
	"github.com/chenhg5/collection"
	"github.com/regcostajr/go-web3"
	"github.com/regcostajr/go-web3/eth/block"
	"github.com/regcostajr/go-web3/providers"
)

var (
	mode    = flag.String("p", "rpc", "rpc or ipc")
	ipcpath = flag.String("d", "chain/geth.ipc", "ipc path")
	rpcurl  = flag.String("h", "127.0.0.1:8545", "rpc url")
)

// go run utils/getBlock.go -p ipc -d chain/geth.ipc
func main() {
	flag.Parse()

	reserved := collection.Collect(constant.ReservedAccounts)

	var connection *web3.Web3

	switch *mode {
	case "rpc":
		connection = web3.NewWeb3(providers.NewHTTPProvider(*rpcurl, 60, false))
	case "ipc":
		connection = web3.NewWeb3(providers.NewIPCProvider(*ipcpath))
	}

	blockNumber, err := connection.Eth.GetBlockNumber()

	if err != nil {
		fmt.Println(err)
		panic("Get block number failure")
	}

	var bn int64
	var accounts = make(map[string]*big.Int)
	for bn = 0; bn < blockNumber.Int64(); bn += 1 {
		blockByNumber, err := connection.Eth.GetBlockByNumber(big.NewInt(bn), false)

		if err != nil {
			fmt.Println(err)
			panic(err)
		}

		if _, ok := accounts[blockByNumber.Miner]; !ok {
			accounts[blockByNumber.Miner] = big.NewInt(0)
		}

		count, err := connection.Eth.GetBlockTransactionCountByHash(blockByNumber.Hash)

		if err != nil {
			fmt.Println(err)
			panic(err)
		}

		if count.Cmp(big.NewInt(0)) > 0 {
			var tc int64
			for tc = 0; tc < count.Int64(); tc += 1 {
				tx, _ := connection.Eth.GetTransactionByBlockHashAndIndex(blockByNumber.Hash, big.NewInt(tc))
				if _, ok := accounts[tx.From]; !ok {
					accounts[tx.From] = big.NewInt(0)
				}
				if _, ok := accounts[tx.To]; !ok {
					accounts[tx.To] = big.NewInt(0)
				}
			}
			if !reserved.Contains(blockByNumber.Miner) {
				fmt.Printf("%5d block has %d tx, miner is %s\n", bn, count.Int64(), blockByNumber.Miner)
			}
		}
	}

	for k, _ := range accounts {
		bal, err := connection.Eth.GetBalance(k, block.LATEST)
		if err == nil {
			accounts[k] = accounts[k].Set(bal)
		}
	}

	for _, acc := range constant.ReservedAccounts {
		if _, ok := accounts[acc]; ok {
			accounts[acc] = big.NewInt(0)
		}
	}

	ac := 0
	space := "                                                        "
	for k, v := range accounts {
		if v.Cmp(big.NewInt(0)) > 0 {
			bal := v.String()
			countTx, _ := connection.Eth.GetTransactionCount(k, block.LATEST)
			fmt.Printf("%4d. [%s] %s Wei %4d Tx\n", ac, k, space[:(30-len(bal))]+bal, countTx)
			ac += 1
		}
	}
}
